using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Text;
using System.Web;
using NVelocity;
using NVelocity.App;
using NVelocity.Runtime;

namespace Sedna.Core.Template
{
    public class NVelocityTemplateProcessor : ITemplateProcessor
    {
        #region Fields
        
        private static VelocityEngine velocityEngine;
        private StreamReader streamToPrint;
        private Font printFont;
        private String templatesDirectory;

        #endregion
        
        public string TemplatesDirectory
        {
            set { templatesDirectory = value; }
        }

        private void InitNVelocity()
        {
            lock(this)
            {
               if (velocityEngine != null) return;

               velocityEngine = new VelocityEngine();
               velocityEngine.SetProperty(RuntimeConstants_Fields.FILE_RESOURCE_LOADER_PATH, HttpContext.Current.Server.MapPath(templatesDirectory));
               velocityEngine.Init();
            }
        }

        #region ProcessTemplate
        
        public void ProcessTemplate(string templateFile, Hashtable data, TextWriter textWriter)
        {
            InitNVelocity();
            VelocityContext context = new VelocityContext(data);
            velocityEngine.MergeTemplate(templateFile, context, textWriter);
        }

        public void ProcessTemplate(string templateFile, String name, ICollection data, TextWriter textWriter)
        {
            InitNVelocity();
            VelocityContext context = new VelocityContext();
            context.Put(name, data);
            velocityEngine.MergeTemplate(templateFile, context, textWriter);
        }

        public void ProcessTemplate(string templateFile, Hashtable data, string fileName)
        {
            StreamWriter writer = new StreamWriter(fileName);
            ProcessTemplate(templateFile, data, writer);
            writer.Close();
        }

        public void ProcessTemplate(string templateFile, string name, object obj, TextWriter textWriter)
        {
            InitNVelocity();
            VelocityContext context = new VelocityContext();
            context.Put(name, obj);
            velocityEngine.MergeTemplate(templateFile, context, textWriter);
        }

        public void ProcessTemplate(string templateFile, TextWriter textWriter, params DictionaryEntry[] entries)
        {
            InitNVelocity();
            VelocityContext context = new VelocityContext();
            foreach (DictionaryEntry entry in entries)
            {
                context.Put(entry.Key.ToString(), entry.Value);
            }
            velocityEngine.MergeTemplate(templateFile, context, textWriter);
        }

        #endregion
        
        public void ProcessAndPrintTemplate(string templateFile, Hashtable data, string printerName, bool isLandscape)
        {
            String tempFile = HttpContext.Current.Server.MapPath("~/PrintCache") + "\\" + System.Guid.NewGuid().ToString() + ".txt";
            ProcessTemplate(templateFile,data,tempFile);
            lock (this)
            {
                printFont = new Font("Courier NEW", 8);
                streamToPrint = new StreamReader(tempFile);
                PrintDocument pd = new PrintDocument();                    
                pd.PrinterSettings.PrinterName = printerName;
                pd.DefaultPageSettings.Landscape = isLandscape;
                
                //Setting up paper size
                foreach (PaperSize ps in pd.PrinterSettings.PaperSizes)
                {
                    if (ps.Kind == PaperKind.Letter)
                        pd.DefaultPageSettings.PaperSize = ps;
                }
                
                
                pd.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);
                pd.Print();
                streamToPrint.Close();
            }
        }

        // The PrintPage event is raised for each page to be printed.
        private void pd_PrintPage(object sender, PrintPageEventArgs ev)
        {
            float linesPerPage = 0;
            float yPos = 0;
            int count = 0;
            float leftMargin = ev.MarginBounds.Left;
            float topMargin = ev.MarginBounds.Top;
            string line = null;

            // Calculate the number of lines per page.
            linesPerPage = ev.MarginBounds.Height /
               printFont.GetHeight(ev.Graphics);

            // Print each line of the file.
            while (count < linesPerPage &&
               ((line = streamToPrint.ReadLine()) != null))
            {
                yPos = topMargin + (count *
                   printFont.GetHeight(ev.Graphics));
                ev.Graphics.DrawString(line, printFont, Brushes.Black,
                   leftMargin, yPos, new StringFormat());
                count++;
            }

            // If more lines exist, print another page.
            if (line != null)
                ev.HasMorePages = true;
            else
                ev.HasMorePages = false;
        }

    }
}
